use crate::item::{Item, ItemRequest,Contact,ContactRequest};
use actix_web::{error,delete,Error, get, post, put, web, HttpResponse, HttpRequest,Responder};
use sqlx::SqlitePool;
use log::info;
use serde_derive::Deserialize;
use serde_json;
use futures::StreamExt;
#[derive(Deserialize)]
pub struct ContactSearchRequest {
   start:i64,
   limit:i64,
   search: String,
   baoxiang:String,
}
const MAX_SIZE: usize = 262_144;
#[post("/rest/Contact/")]
async fn create_contact(mut payload: web::Payload,    db_pool: web::Data<SqlitePool>) -> Result<HttpResponse, Error> {
    let mut body = web::BytesMut::new();
    while let Some(chunk) = payload.next().await {
        let chunk = chunk?;
        // limit max size of in-memory payload
        if (body.len() + chunk.len()) > MAX_SIZE {
            return Err(error::ErrorBadRequest("overflow"));
        }
        body.extend_from_slice(&chunk);
    }
    info!("create contact");

    // body is loaded, now we can deserialize serde-json
    // let item = serde_json::from_slice::<ContactRequest>(&body)?;
    // let v: Value = serde_json::from_str(&body)?;
    let s = match String::from_utf8(body.to_vec()) {
        Ok(v) => v,
        Err(e) => String::from(""),
    };
    info!("{}",s);
    let r:Result<serde_json::Value, serde_json::Error> = serde_json::from_slice(&body);
    match r {
        Ok(item) =>{
            info!("{}",item);
            let result = Contact::create(item, db_pool.get_ref()).await;
            match result {
                Ok(item1) =>{
                    info!("{},{}",item1.id,item1.yonghu);
                    return Ok(HttpResponse::Ok().body("success:true"));
                },
                Err(v)=> {
                    info!("{}",v);
                    return Ok(HttpResponse::Ok().body("success:false"));
                },
            }           
            // return Ok(HttpResponse::BadRequest().body("Error trying to create new item"));
        },
        Err(v)=> {
            info!("{}",v);
            return Ok(HttpResponse::Ok().body(v.to_string()));
        },
    }
    
}
#[delete("/rest/Contact/{id}")]
async fn delete_contact(id: web::Path<i64>,    db_pool: web::Data<SqlitePool>) -> Result<HttpResponse, Error> {
    info!("delete contact");
    let result = Contact::delete(id.into_inner(), db_pool.get_ref()).await;
    match result {
        Ok(item1) =>{
            info!("{}",item1);
            return Ok(HttpResponse::Ok().body("success:true"));
        },
        Err(v)=> {
            info!("{}",v);
            return Ok(HttpResponse::Ok().body("success:false"));
        },
    }           
}

#[put("/rest/Contact/")]
async fn update_contact(mut payload: web::Payload,    db_pool: web::Data<SqlitePool>) -> Result<HttpResponse, Error> {
    let mut body = web::BytesMut::new();
    while let Some(chunk) = payload.next().await {
        let chunk = chunk?;
        // limit max size of in-memory payload
        if (body.len() + chunk.len()) > MAX_SIZE {
            return Err(error::ErrorBadRequest("overflow"));
        }
        body.extend_from_slice(&chunk);
    }
    info!("create contact");

    // body is loaded, now we can deserialize serde-json
    // let item = serde_json::from_slice::<ContactRequest>(&body)?;
    // let v: Value = serde_json::from_str(&body)?;
    let s = match String::from_utf8(body.to_vec()) {
        Ok(v) => v,
        Err(e) => String::from(""),
    };
    info!("{}",s);
    let r:Result<serde_json::Value, serde_json::Error> = serde_json::from_slice(&body);
    match r {
        Ok(item) =>{
            info!("{}",item);
            let result = Contact::update(item, db_pool.get_ref()).await;
            match result {
                Ok(item1) =>{
                    info!("{},{}",item1.id,item1.yonghu);
                    return Ok(HttpResponse::Ok().body("success:true"));
                },
                Err(v)=> {
                    info!("{}",v);
                    return Ok(HttpResponse::Ok().body("success:false"));
                },
            }           
            // return Ok(HttpResponse::BadRequest().body("Error trying to create new item"));
        },
        Err(v)=> {
            info!("{}",v);
            return Ok(HttpResponse::Ok().body(v.to_string()));
        },
    }
    
}
#[get("/rest/Contact/")]
async fn get_contacts(web::Query(info1): web::Query<ContactSearchRequest>,db_pool: web::Data<SqlitePool>) -> impl Responder {
    info!("get_contacts");
    // let limit=3;
    // let offset=0;
    let result = Contact::get(db_pool.get_ref(),info1.start,info1.limit).await;
    match result {
        Ok(items) => HttpResponse::Ok().json(items),
        _ => HttpResponse::BadRequest()
            .body("Error trying to read all items from database"),
    }
}

#[get("/rest/Item/")]
async fn get_items(db_pool: web::Data<SqlitePool>) -> impl Responder {
    let result = Item::find_all(db_pool.get_ref()).await;
    match result {
        Ok(items) => HttpResponse::Ok().json(items),
        _ => HttpResponse::BadRequest()
            .body("Error trying to read all items from database"),
    }
}
// url 解析
#[derive(Deserialize)]
pub struct SqlRequest {
   cmd: String,
}

#[get("/rest/sql/")]
async fn rest_sql(web::Query(info1): web::Query<SqlRequest>,db_pool: web::Data<SqlitePool>) -> impl Responder {
    // info!("{}",req.match_info());
    // info!("REQ: {:?}", req);
    // info!("{}",info1.cmd);
    // let r = req.match_info().get("cmd");
    // match r {
    //     None =>HttpResponse::Ok().json(info.cmd),
    //     Some(cmd)=> HttpResponse::Ok().json(1),
    // }   
    // HttpResponse::Ok().json("hello")
    // info!("{}",cmd);
    let result = Item::sql(info1.cmd,db_pool.get_ref()).await;
    match result {
        Ok(items) => HttpResponse::Ok().json(items),
        _ => HttpResponse::BadRequest()
            .body("Error trying to read all items from database"),
    }
}


#[get("/item/{id}")]
async fn find_item(id: web::Path<i64>, db_pool: web::Data<SqlitePool>) -> impl Responder {
    let result = Item::find_by_id(id.into_inner(), db_pool.get_ref()).await;
    match result {
        Ok(item) => HttpResponse::Ok().json(item),
        _ => HttpResponse::BadRequest().body("Item not found"),
    }
}

#[post("/rest/Item/")]
async fn create_item(
    item: web::Json<ItemRequest>,
    db_pool: web::Data<SqlitePool>,
) -> impl Responder {
    info!("create");
    let result = Item::create(item.into_inner(), db_pool.get_ref()).await;
    match result {
        Ok(item) => HttpResponse::Ok().json(item),
        Err(v)=> {
            info!("{}",v);
            return HttpResponse::BadRequest().body("Error trying to create new item");
        },
    }
}

#[put("/rest/Item/")]
async fn update_item(
    item: web::Json<Item>,
    db_pool: web::Data<SqlitePool>,
) -> impl Responder {
    info!("{}",item.id);
    // HttpResponse::Ok().json("update")
    let result =
        Item::update(item.into_inner(), db_pool.get_ref()).await;
    match result {
        Ok(item) => HttpResponse::Ok().json(item),
        _ => HttpResponse::BadRequest().body("Item not found"),
    }
}

#[delete("/item/{id}")]
async fn delete_item(id: web::Path<i64>, db_pool: web::Data<SqlitePool>) -> impl Responder {
    let result = Item::delete(id.into_inner(), db_pool.get_ref()).await;
    match result {
        Ok(rows) => {
            if rows > 0 {
                HttpResponse::Ok()
                    .body(format!("Successfully deleted {} record(s)", rows))
            } else {
                HttpResponse::BadRequest().body("Item not found")
            }
        }
        _ => HttpResponse::BadRequest().body("Item not found"),
    }
}

// function that will be called on new Application to configure routes for this module
pub fn init(cfg: &mut web::ServiceConfig) {
    cfg.service(get_items);
    cfg.service(find_item);
    cfg.service(create_item);
    cfg.service(update_item);
    cfg.service(delete_item);
    cfg.service(rest_sql);
    cfg.service(get_contacts);
    cfg.service(create_contact);
    cfg.service(update_contact);
    cfg.service(delete_contact);
    info!("after item init");
}
